package com.guit.hrms.service.impl;


import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.guit.hrms.dto.LocationCheckInDTO;
import com.guit.hrms.dto.SetCheckInTimeDTO;
import com.guit.hrms.dto.TransactionDTO;
import com.guit.hrms.mapper.*;
import com.guit.hrms.po.*;
import com.guit.hrms.po.utilsPO.PageBean;
import com.guit.hrms.service.AttendanceService;
import com.guit.hrms.service.DepartmentService;
import com.guit.hrms.utils.EmailUtil;
import com.guit.hrms.utils.JudgeUtil;
import com.guit.hrms.utils.ThreadLocalUtil;
import com.guit.hrms.utils.TimeDifferenceUtil;
import com.guit.hrms.vo.EmpSignVO;
import com.guit.hrms.vo.EmployeeVO;
import com.guit.hrms.vo.TransactionVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Time;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AttendanceServiceImpl implements AttendanceService {
    @Autowired
    private AttendanceMapper attendanceMapper;
    @Autowired
    private GuitLocation guitLocation;
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private DepartmentMapper departmentMapper;
    @Autowired
    private AcademyMapper academyMapper;
    @Autowired
    private OtherDeptMapper otherDeptMapper;
    @Autowired
    private QueryMapper queryMapper;
    @Autowired
    private EmailUtil emailUtil;
    @Value("${spring.mail.username1}")
    private String username1;

    /**
     * 设置打卡时间
     * @param setCheckInTimeDTO setCheckInTimeDTO 设置打卡时间的信息
     * @return Integer 1成功，0失败
     */
    @Override
    public Integer setCheckInTime(SetCheckInTimeDTO setCheckInTimeDTO) {
        int result = 0;
        if (setCheckInTimeDTO.getSetDeptType() == 1){
            result = departmentMapper.selectDepartmentById(setCheckInTimeDTO.getSetDeptId()) == null ? 0 :  1;
        } else if (setCheckInTimeDTO.getSetDeptType() == 2) {
            result = academyMapper.getAcademyById(setCheckInTimeDTO.getSetDeptId()) == null ? 0 :  1;
        } else if (setCheckInTimeDTO.getSetDeptType() == 3) {
            result = otherDeptMapper.getOtherDeptById(setCheckInTimeDTO.getSetDeptId()) == null ? 0 :  1;
        } else {
            throw new RuntimeException("部门类型错误");
        }
        if (result == 0) {
            throw new RuntimeException("部门不存在");
        }
        if (attendanceMapper.getCheckInTime(setCheckInTimeDTO.getSetDeptId(), setCheckInTimeDTO.getSetDeptType()) != null) {
//            System.out.println(attendanceMapper.updateCheckInTime(setCheckInTimeDTO));
            return attendanceMapper.updateCheckInTime(setCheckInTimeDTO);
        } else {
            return attendanceMapper.addCheckInTime(setCheckInTimeDTO);
        }

    }

    /**
     * 判断是否在打卡日的打卡时间内
     * @param deptId 部门id
     * @param deptType 部门类型
     * @return Integer 1是，0不是
     */
    @Override
    public SetCheckInTimeDTO getCheckInTime(Integer deptId, Integer deptType) {
        return attendanceMapper.getCheckInTime(deptId, deptType);
    }

    /**
     * 获取各部门的打卡设置信息
     * @param page 页码
     * @param pageSize 每页大小
     * @param deptType 部门类型
     * @param deptId 部门id
     * @return 结果
     */
    @Override
    public PageBean getAllCheckInTime(Integer page, Integer pageSize, Integer deptId, Integer deptType) {
        PageHelper.startPage(page, pageSize);
        List<SetCheckInTimeDTO> checkInTimeDTOList = attendanceMapper.getAllRecords(deptId, deptType);
        Page<SetCheckInTimeDTO> p = (Page<SetCheckInTimeDTO>) checkInTimeDTOList;
        return new PageBean(p.getTotal(), p.getResult());
    }

    /**
     * 统计指定月份的打卡记录
     * @param lastYearMonth 年份月份
     */
    @Override
    @Transactional
    public void countAttendanceByMonth(LocalDate lastYearMonth) {
        List<EmployeeVO> employees = queryMapper.query(0,0,0);
        AttendanceStatistics attendanceStatistics = null;
        List<AttendanceStatistics> attendanceStatisticsList = new ArrayList<>();
        List<EmpSign> empSigns = null;
        Integer lateCount = 0;
        Integer leaveEarlyCount = 0;
        Integer absentDays = 0;
        Integer attendanceDays = 0;
        Integer leaveDays = 0;
        String workingTime = "00:00:00";
        String overTime = "00:00:00";
        Integer result = 0;
        for (EmployeeVO employee : employees) {
//            empSigns = null;
            lateCount = 0;
            leaveEarlyCount = 0;
            absentDays = 0;
            attendanceDays = 0;
            leaveDays = 0;
            workingTime = "00:00:00";
            overTime = "00:00:00";
            empSigns = attendanceMapper.countAttendanceByMonth(employee.getEmployeeId(), lastYearMonth);
            for (EmpSign empSign : empSigns) {
                switch (empSign.getCheckInStatus()){
                    case 4:
                        lateCount++;
                        break;
                    case 5:
                        leaveEarlyCount++;
                        break;
                    case 6:
                        lateCount++;
                        leaveEarlyCount++;
                        break;
                }
                if (empSign.getIsCheckIn() == 1){
                    attendanceDays++;
                } else {
                    absentDays++;
                }
                if (empSign.getCircumstance() != 1){
                    leaveDays++;
                }
                workingTime = TimeDifferenceUtil.addTimes(workingTime, empSign.getWorkingTime().toString());
                overTime = TimeDifferenceUtil.addTimes(overTime, empSign.getOverTime().toString());
            }
            attendanceStatistics = new AttendanceStatistics();
            attendanceStatistics.setEmployeeId(employee.getEmployeeId());
            attendanceStatistics.setYearMonth(lastYearMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")));
            attendanceStatistics.setLateCount(lateCount);
            attendanceStatistics.setLeaveEarlyCount(leaveEarlyCount);
            attendanceStatistics.setAbsentDays(absentDays);
            attendanceStatistics.setAttendanceDays(attendanceDays);
            attendanceStatistics.setLeaveDays(leaveDays);
            attendanceStatistics.setWorkingTime(workingTime);
            attendanceStatistics.setOverTime(overTime);
            attendanceStatisticsList.add(attendanceStatistics);
        }
        for (AttendanceStatistics attendanceStatistics1 : attendanceStatisticsList) {
            result = attendanceMapper.insertAttendanceStatistics(attendanceStatistics1);
            if (result == 0){
                ToEmail toEmail = new ToEmail();
                List<String> emails = new ArrayList<>();
                emails.add(username1);
                toEmail.setTos(emails.toArray(new String[0]));
                toEmail.setSubject("员工考勤统计插入失败");
                toEmail.setContent("员工考勤统计插入失败: 员工工号"+ attendanceStatistics1.getEmployeeId());
                emailUtil.sendSimpleEmail(toEmail);
                log.error("员工考勤统计插入失败: 员工工号{}", attendanceStatistics1.getEmployeeId());
//                throw new RuntimeException("员工考勤统计插入失败");
            }
        }
    }

    /**
     * 获取所有考勤统计信息
     * @param page 页数
     * @param pageSize 每页大小
     * @param employeeId 员工工号
     * @param yearMonth 年月
     * @param deptId 部门id
     * @param academyId 学院id
     * @param otherDeptId 其他部门id
     * @return 结果
     */
    @Override
    public PageBean getAllAttendanceStatistics(Integer page, Integer pageSize, String employeeId, String yearMonth, Integer deptId, Integer academyId, Integer otherDeptId) {
        List<EmployeeVO> employeeVOS = null;
        List<String> employeeIds = new ArrayList<>();
//        System.out.println("---"+(employeeId.toString()) +" "+ yearMonth.isBlank());
//        System.out.println(page+ " " + pageSize+ " " +employeeId+" "+yearMonth+" "+deptId+" "+academyId+" "+otherDeptId);
        if (deptId != null && employeeId.isBlank()){
            employeeVOS = queryMapper.query(deptId,1,0);
            employeeIds = employeeVOS.stream()
                    .map(EmployeeVO::getEmployeeId)
                    .toList();
        } else if (academyId != null && employeeId.isBlank()){
            employeeVOS = queryMapper.query(academyId,2,0);
            employeeIds = employeeVOS.stream()
                    .map(EmployeeVO::getEmployeeId)
                    .toList();
        } else if (otherDeptId != null && employeeId.isBlank()){
            employeeVOS = queryMapper.query(otherDeptId,3,0);
            employeeIds = employeeVOS.stream()
                    .map(EmployeeVO::getEmployeeId)
                    .toList();
        } else {
            if (employeeId != null){
                employeeIds.add(employeeId);
            }
        }
        PageHelper.startPage(page, pageSize);
        List<AttendanceStatistics> attendanceStatistics = attendanceMapper.getAllAttendanceStatistics(employeeIds, yearMonth);
        Page<AttendanceStatistics> p = (Page<AttendanceStatistics>) attendanceStatistics;
        return new PageBean(p.getTotal(), p.getResult());
    }

    /**
     * 获取员工个人当天考勤记录
     * @return 员工个人当天考勤记录
     */
    @Override
    public EmpSignVO getPersonalRecords(String employeeId) {
        return attendanceMapper.getPersonalRecords(employeeId, LocalDate.now());
    }

    /**
     * 增加员工打卡记录
     * @param checkInDate 打卡日期
     */
    @Override
    public void addEmpSign(LocalDate checkInDate) {
        List<EmployeeVO> employeeVOS = queryMapper.query(0,0,0);
        List<SetCheckInTimeDTO> checkInStandards = attendanceMapper.getAllRecords(0,0);
        SetCheckInTimeDTO checkInStandard = null;
        Integer result = 0;
        for (EmployeeVO employeeVO : employeeVOS) {
            checkInStandard = checkInStandards.stream()
                    .filter(setCheckInTimeDTO -> setCheckInTimeDTO.getSetDeptId().equals(employeeVO.getDepartment()))
                    .filter(setCheckInTimeDTO -> setCheckInTimeDTO.getSetDeptType().equals(employeeVO.getDeptType()))
                    .findFirst()
                    .orElse(null);
            if (checkInStandard != null && checkInStandard.getSetStartDate().isBefore(checkInDate) && checkInStandard.getSetEndDate().isAfter(checkInDate)){
                result = attendanceMapper.addEmpSign(employeeVO.getEmployeeId(), checkInDate);
            }
        }
    }

    /**
     * 定位打卡
     * 判断是否在设置的打卡范围内，并根据参数内容进行对应的上下班打卡操作
     * @param locationCheckInDTO 定位打卡的信息
     * @return Integer 1成功，0失败
     */
    @Override
    public Integer locationCheckIn(LocationCheckInDTO locationCheckInDTO) {
        if(locationCheckInDTO.getEmployeeId()!=null && locationCheckInDTO.getCheckInDate()!=null &&(locationCheckInDTO.getOnWorkTime()!=null || locationCheckInDTO.getOffDutyTime()!=null)){
            if (JudgeUtil.isWithinRadius(locationCheckInDTO.getLatitude(),
                    locationCheckInDTO.getLongitude(),
                    guitLocation.getLatitude(),
                    guitLocation.getLongitude(),
                    guitLocation.getRadius()
            )){
                //获取该员工对应部门的签到标准要求
                SetCheckInTimeDTO checkInStandard = attendanceMapper.getTimeById(locationCheckInDTO.getDeptId(), locationCheckInDTO.getDeptType());
                if (checkInStandard != null){ // 员工所在部门设置打卡要求
                    if (locationCheckInDTO.getOffDutyTime()!=null){ // 下班打卡
                        LocationCheckInDTO locationCheckInDTO1 = attendanceMapper.getById(locationCheckInDTO);
                        if (locationCheckInDTO1 != null){
                            LocalTime onWorkTime = locationCheckInDTO1.getOnWorkTime();
                            if (onWorkTime.isAfter(checkInStandard.getSetStartTime()) && locationCheckInDTO.getOffDutyTime().isBefore(checkInStandard.getSetEndTime())){
                                locationCheckInDTO.setCheckInStatus(6); // 迟到加早退
                                locationCheckInDTO.setIsCheckIn(1); //当天已签到
                                //计算时间差
                                LocalTime workingTime = TimeDifferenceUtil.compute(onWorkTime, locationCheckInDTO.getOffDutyTime());
                                locationCheckInDTO.setWorkingTime(workingTime);
                            } else if (onWorkTime.isAfter(checkInStandard.getSetStartTime())){
                                locationCheckInDTO.setCheckInStatus(4); //迟到
                                locationCheckInDTO.setIsCheckIn(1); //当天已签到
                                //计算时间差
                                LocalTime workingTime = TimeDifferenceUtil.compute(onWorkTime, locationCheckInDTO.getOffDutyTime());
                                locationCheckInDTO.setWorkingTime(workingTime);
                            } else if (locationCheckInDTO.getOffDutyTime().isBefore(checkInStandard.getSetEndTime())){
                                locationCheckInDTO.setCheckInStatus(5); //早退
                                locationCheckInDTO.setIsCheckIn(1); //当天已签到
                                //计算时间差
                                LocalTime workingTime = TimeDifferenceUtil.compute(onWorkTime, locationCheckInDTO.getOffDutyTime());
                                locationCheckInDTO.setWorkingTime(workingTime);
                            } else {
                                locationCheckInDTO.setCheckInStatus(2); //已下班
                                locationCheckInDTO.setIsCheckIn(1); //当天已签到
                                //计算时间差
                                LocalTime workingTime = TimeDifferenceUtil.compute(onWorkTime, locationCheckInDTO.getOffDutyTime());
                                locationCheckInDTO.setWorkingTime(workingTime);

                                LocalTime standardWorkingTime = TimeDifferenceUtil.compute(checkInStandard.getSetStartTime(),checkInStandard.getSetEndTime());

                                if(workingTime.compareTo(standardWorkingTime) == 1){
                                    locationCheckInDTO.setOverTime(TimeDifferenceUtil.compute(standardWorkingTime,workingTime));
                                }
                            }
                            return attendanceMapper.locationCheckIn2(locationCheckInDTO);
                        } else {
                            return 0;
                        }
                    } else if(locationCheckInDTO.getOnWorkTime()!=null){ //上班打卡
                        if (attendanceMapper.selectSign(locationCheckInDTO)==1){ //有特殊情况
                            return attendanceMapper.locationCheckIn3(locationCheckInDTO);
                        } else { //没有特殊情况
                            LocationCheckInDTO locationCheckInDTO1 = attendanceMapper.getById(locationCheckInDTO);
                            if (locationCheckInDTO1 == null){
                                return attendanceMapper.locationCheckIn(locationCheckInDTO);
                            } else {
                                return attendanceMapper.locationCheckIn1(locationCheckInDTO);
                            }
                        }
                    } else {
                        return 0;
                    }
                } else {
                    return 2;
                }
            } else {
                return 0;
            }
        } else {
            return 0;
        }
    }



    /**
     * 获取所有考勤记录
     * @return 所有员工的考勤记录
     */
    @Override
    public PageBean getRecords(Integer page, Integer pageSize, LocalDate checkInDate, Integer isCheckIn, Integer checkInStatus, Integer circumstance) {
        PageHelper.startPage(page, pageSize);
        List<EmpSign> empSignList = attendanceMapper.getRecords(checkInDate, isCheckIn, checkInStatus, circumstance);
        Page<EmpSign> p = (Page<EmpSign>) empSignList;
        return new PageBean(p.getTotal(), p.getResult());
    }

    /**
     * 获取单个员工考勤记录
     * @return 单个员工的考勤记录
     */
    @Override
    public List<EmpSign> getRecordsById(String employeeId) {
        List<EmpSign> empSignList = attendanceMapper.getRecordsById(employeeId);
        return empSignList;
    }

    /**
     * 事务申请
     * @param transaction 事务申请
     */
    @Override
    public Integer affairs(Transaction transaction) {
        Map<String,Object> map = ThreadLocalUtil.get();
        String employeeId = (String) map.get("employeeId");
        String employeeName = (String) map.get("username");
        Integer deptId = (Integer) map.get("department");
        transaction.setEmployeeId(employeeId);
        transaction.setEmployeeName(employeeName);
        transaction.setDeptId(deptId);
        String deptName = departmentService.selectDepartment(deptId).getDeptName();
        transaction.setDeptName(deptName);
        transaction.setApplyTime(LocalDateTime.now());
//        transaction.setApprovalStatus(0);
//        transaction.setRevokeStatus(0);
//        transaction.setApprovalInstructions(transaction.getApprovalInstructions());
        System.out.println("transaction = " + transaction);
        attendanceMapper.affairs(transaction);
        return transaction.getId();
    }

    /**
     * 个人查看事务表
     * @param page 当前页
     * @param pageSize 每页显示条数
     * @param type 事务类型
     * @param approvalStatus 审批状态
     * @param revokeStatus 销假状态
     * @param extensionStatus 延期状态
     * @return 事务表
     */
    @Override
    public PageBean getTransaction(Integer page, Integer pageSize, Integer type, Integer approvalStatus, Integer revokeStatus, Integer extensionStatus) {
        Map<String,Object> map = ThreadLocalUtil.get();
        String employeeId = (String) map.get("employeeId");
        PageHelper.startPage(page,pageSize);
        Transaction transaction = new Transaction();
        transaction.setEmployeeId(employeeId);
        transaction.setType(type);
        transaction.setApprovalStatus(approvalStatus);
        transaction.setRevokeStatus(revokeStatus);
        transaction.setExtensionStatus(extensionStatus);

        List<TransactionVO> transactions = attendanceMapper.getTransactionById(transaction);

        Page<TransactionVO> p =(Page<TransactionVO>) transactions;

        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());

        // 打印日志，检查数据
        System.out.println("Transactions: " + transactions);
        System.out.println("PageBean: " + pageBean);
        return pageBean;
    }

    /**
     * 删除自己的请假记录
     * @param ids 要删除的事务id
     */
    @Override
    public void deleteLeaveRecord(List<Integer> ids) {
        Map<String,Object> map = ThreadLocalUtil.get();
        String employeeId = (String) map.get("employeeId");
        attendanceMapper.deleteTransactionByIds(employeeId,ids);
    }

    /**
     * 自己的销假
     * @param id 要销假记录的id
     * @return 结果
     */
    @Override
    public Integer cancelTransaction(Integer id) {
        Map<String,Object> map = ThreadLocalUtil.get();
        String employeeId = (String) map.get("employeeId");
        Transaction transaction = new Transaction();
        transaction.setId(id);
        transaction.setEmployeeId(employeeId);
        transaction.setCancelTime(LocalDateTime.now());
        transaction.setRevokeStatus(1);
        Integer result = attendanceMapper.cancelTransaction(transaction);
        if (result == 0){
            return 0;
        } else {
            return 1;
        }
    }

    /**
     * 更新事务
     * @param transaction 更新的内容
     * @return 结果
     */
    @Override
    public Integer updateTransaction(Transaction transaction) {
        TransactionVO transactionVO = attendanceMapper.getTransactionById2(transaction.getId());
        if(transactionVO.getApprovalStatus() == 0){
            return attendanceMapper.updateTransaction(transaction);
        } else if (transactionVO.getApprovalStatus() == 1 || transactionVO.getApprovalStatus() == 2){
            if(transactionVO.getRevokeStatus() == 0 || transactionVO.getRevokeStatus() == 3){
                transaction.setPostponedTime(transaction.getEndTime());
                transaction.setExtensionTime(LocalDateTime.now());
                transaction.setEndTime(null);
                transaction.setExtensionStatus(1);
                return attendanceMapper.updateTransaction(transaction);
            } else {
                return 0;
            }
        } else {
            return 0;
        }
    }

    /**
     * 修改请假原因
     * @param transactionDTO 事务id和原因
     * @param employeeId 员工id
     * @return 结果
     */
    @Override
    public Integer updateTransactionReason(TransactionDTO transactionDTO, String employeeId) {
        return attendanceMapper.updateTransactionReason(transactionDTO.getId(),transactionDTO.getReason(),employeeId);
    }
}
